using System;
using System.Collections.Generic;
using System.ComponentModel.Design;
using System.Diagnostics;
using System.Xml;
using EnvDTE;
using Microsoft.Practices.ComponentModel;
using Microsoft.Practices.RecipeFramework.Library;
using Microsoft.Practices.RecipeFramework.Services;
using PrismFactory.SoftwareFactory.Properties;
using Action = Microsoft.Practices.RecipeFramework.Configuration.Action;

namespace PrismFactory.SoftwareFactory.Extensions.Coordinators
{
    /// <summary>
    /// Action coordination for boolean conditions.
    /// </summary>
    [ServiceDependency(typeof (DTE))]
    [ServiceDependency(typeof (IActionExecutionService))]
    public class ConditionalCoordinator : SitedComponent, IActionCoordinationService
    {
        /// <summary>
        /// The condition attribute name
        /// </summary>
        public const string ConditionalAttributeName = "Condition";

        private DTE visualStudio;

        /// <summary>
        /// When implemented by a class, allows descendants to
        /// perform processing whenever the component is being sited.
        /// </summary>
        protected override void OnSited()
        {
            base.OnSited();
            visualStudio = GetService<DTE>(true);
        }

        /// <summary>
        /// Runs the coordination using the configuration data specified in the configuration file.
        /// </summary>
        /// <param name="declaredActions">Actions defined in the package configuration file for the currently executing recipe.</param>
        /// <param name="coordinationData">The configuration data used to setup the coordination.</param>
        public void Run(Dictionary<string, Action> declaredActions,
                        XmlElement coordinationData)
        {
            var exec = GetService<IActionExecutionService>(true);
            int amountCompleted = 0;

            try
            {
                foreach (Action action in declaredActions.Values)
                {
                    amountCompleted++;
                    visualStudio.StatusBar.Progress(true, Resources.StatusBarProgressMessage, amountCompleted, declaredActions.Values.Count);

                    bool execute = (action.AnyAttr == null || action.AnyAttr.Length == 0);

                    if (!execute)
                    {
                        var dictservice = (IDictionaryService) GetService(typeof (IDictionaryService));
                        var evaluator = new ExpressionEvaluationService();
                        execute = true;
                        foreach (XmlAttribute att in action.AnyAttr)
                        {
                            if (att.Name.Equals(ConditionalAttributeName, StringComparison.InvariantCultureIgnoreCase))
                            {
                                try
                                {
                                    execute = (bool) evaluator.Evaluate(att.Value, new ServiceAdapterDictionary(dictservice));
                                }
                                catch (Exception e)
                                {
                                    execute = false;
                                    Trace.TraceWarning(Resources.InvalidConditionException, e.Message, e.StackTrace);
                                }
                                break;
                            }
                        }
                    }

                    if (execute)
                    {
                        Trace.TraceInformation(Resources.ExecutingAction, action.Name);
                        exec.Execute(action.Name);
                    }
                }
            }
            finally
            {
                visualStudio.StatusBar.Progress(false, "", 0, 0);
            }
        }
    }
}